package com.example.spring;

import com.example.spring.dao.ProductDao;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class TransactionManager {

    private static class TransactionInvocationHandler implements InvocationHandler {
        private final Object target;

        public TransactionInvocationHandler(Object target) {
            this.target = target;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.isAnnotationPresent(Transactional.class)) {
                return handleWithTransaction(method, args);
            }
            return method.invoke(target, args);
        }

        private Object handleWithTransaction(Method method, Object[] args) throws Throwable {
            System.out.println("JDK Proxy: 开启事务 - " + method.getName());
            try {
                Object result = method.invoke(target, args);
                System.out.println("JDK Proxy: 提交事务 - " + method.getName());
                return result;
            } catch (Exception e) {
                System.out.println("JDK Proxy: 回滚事务 - " + method.getName());
                throw e;
            }
        }
    }

    private static class TransactionInterceptor implements MethodInterceptor {
        private final Object target;

        public TransactionInterceptor(Object target) {
            this.target = target;
        }

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            if (method.isAnnotationPresent(Transactional.class)) {
                return handleWithTransaction(method, args, proxy);
            }
            return proxy.invoke(target, args);
        }

        private Object handleWithTransaction(Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("CGLIB Proxy: 开启事务 - " + method.getName());
            try {
                Object result = proxy.invoke(target, args);
                System.out.println("CGLIB Proxy: 提交事务 - " + method.getName());
                return result;
            } catch (Exception e) {
                System.out.println("CGLIB Proxy: 回滚事务 - " + method.getName());
                throw e;
            }
        }
    }

    @SuppressWarnings("unchecked")
        public static <T> T getProxy(T target) {
            Class<?> targetClass = target.getClass();
            Class<?>[] interfaces = targetClass.getInterfaces();

            if (interfaces != null && interfaces.length > 0) {
                return (T) Proxy.newProxyInstance(
                        targetClass.getClassLoader(),
                        interfaces,
                        new TransactionInvocationHandler(target));
            } else {
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(targetClass);
                enhancer.setCallback(new TransactionInterceptor(target));

                // 尝试使用无参构造器
                try {
                    return (T) enhancer.create();
                } catch (Exception e) {
                    // 如果失败，尝试使用带参数的构造器
                    try {
                        // 这里假设我们知道构造器参数类型
                        Constructor<?> constructor = targetClass.getDeclaredConstructor(ProductDao.class);
                        Object arg = targetClass.getMethod("getProductDao").invoke(target);
                        return (T) enhancer.create(new Class[]{ProductDao.class}, new Object[]{arg});
                    } catch (Exception ex) {
                        throw new RuntimeException("Failed to create proxy", ex);
                    }
                }
            }
        }
}